﻿/**
*
*@author 许猛
*/

#pragma once
#include <sstream>
#include <string>
#include <boost/static_assert.hpp>
#include "boost/date_time/local_time/local_time.hpp"
#include "GSE_Predefines.h"

//
// 使用者可以增加或者删除类型，但是要保证 LogLevel 和 LOG_LEVEL_NAMES 是一样多
// --可修改区域--
enum LogLevel {
	LOG_GSE_CRITICAL,
	LOG_GSE_IMPORTANT,
	USER_CRITICAL,
	USER_IMPORTANT,
	USER_INFO,
	LOG_LEVELMAX
};

static const tchar * LOG_LEVEL_NAMES[] =
{
	TEXT("GSE_CRITICAL"),
	TEXT("GSE_IMPORTANT"),
	TEXT("USER_CRITICAL"),
	TEXT("USER_IMPORTANT"),
	TEXT("USER_INFO"),
};
// --------------
namespace GSE
{
	// 如果要实现自己的 LogSink，则需要实现这个类
	// Log 提供3个默认 Sink
	// 1. Console, 2.Window, 3. File
	// SinkFile example:
	//		SetSinkParam("Folder=c:\\log;");
	//		SetSinkParam("Header=gate_;");
	//		SetSinkParam("Tail=.log;");
	class ILogSink
	{
	public:
		virtual void Write(int c)	= 0;
		virtual void Flush()		= 0;

		virtual const char * SinkName() = 0;
		virtual void SetSinkParam(const char *)		= 0;		// Sink 需要的额外参数
		virtual void SetSinkParam(const wchar_t *)	= 0;		// 宽字节版本

		GSE_INTERFACE_NONCOPY(ILogSink);
	};

	class GSE_DLL_API GSE_NOVTABLE ILogSystem
	{
	public:
		static ILogSystem * CreateModule();		// 控制生命周期
		static void DestroyModule();

		static ILogSystem* InstancePtr();

		virtual void RegisterSink(ILogSink *) = 0;
		virtual ILogSink* UnRegisterSink(const char * strSinkName) = 0;
		virtual ILogSink* GetSink(const char * strSinkName)		= 0;	
		virtual void SetSink(const char * strSinkName)			= 0;

		virtual void PrintFile(bool bFile) = 0;
		virtual void PrintLine(bool bLine) = 0;
		virtual void PrintTime(bool bTime) = 0;

		virtual bool IsPrintFile() = 0;
		virtual bool IsPrintLine() = 0;
		virtual bool IsPrintTime() = 0;

		virtual void OpenLevel(LogLevel eLevel,bool bOpen)	= 0;
		virtual bool IsOpenLevel(LogLevel eLevel)			= 0;

		virtual void Write(const char * )		= 0;
		virtual void Write(const wchar_t *)		= 0;

	protected:
		ILogSystem() {}
		virtual ~ILogSystem() {}

	private:
		ILogSystem( const ILogSystem& );
		const ILogSystem& operator=( const ILogSystem& );
	};



	class LogFinisher;
	class LogMessage
	{
	public:
		LogMessage(LogLevel eLevel, const char* strFileName,long uLine):
		  m_LogLevel(eLevel), m_LogFileName(strFileName), m_LogCurrentLine(uLine){}
		  ~LogMessage(){}

		  template<class T>
		  LogMessage& operator<<(T value)
		  {
			  m_Message<<value;
			  return *this;
		  }

	private:
		friend class LogFinisher;
		void Finish()
		{
			if (ILogSystem::InstancePtr()->IsOpenLevel(m_LogLevel))
			{
				// 确保LOG_LEVEL_NAMES的数量等于 LogLevel 
				BOOST_STATIC_ASSERT(sizeof(LOG_LEVEL_NAMES) / sizeof(tchar *) == LOG_LEVELMAX);
				std::basic_ostringstream<tchar> oss;

				// 输出时间 和 对应的LOG_LEVEL_NAMES，如果对格式不满意，可以直接修改下面的代码
				// -- 可修改区域 --
				if (ILogSystem::InstancePtr()->IsPrintTime())
				{
					boost::posix_time::ptime pt = boost::posix_time::second_clock::local_time();
					std::basic_string<tchar> strTime = boost::posix_time::to_simple_string_type<tchar>(pt).substr(12);
					oss << strTime.c_str();
				}
				oss << TEXT("[")<<LOG_LEVEL_NAMES[m_LogLevel] << TEXT("]");
				// ----------------
				if (ILogSystem::InstancePtr()->IsPrintFile() || ILogSystem::InstancePtr()->IsPrintLine())
				{
					oss << '(';
					if (ILogSystem::InstancePtr()->IsPrintFile())
						oss << m_LogFileName << ',';
					if (ILogSystem::InstancePtr()->IsPrintLine())
						oss << m_LogCurrentLine;
					oss << ')';
				}
				oss << m_Message.str() << TEXT('\n');
				// 请保证一次性调用 Write()，否则需要在多线程下加锁以保证完整性
				ILogSystem::InstancePtr()->Write(oss.str().c_str());
			}
		}

		LogLevel		m_LogLevel;
		const char*	m_LogFileName;
		long			m_LogCurrentLine;
		std::basic_ostringstream<tchar> m_Message;
	};

	class LogFinisher {
	public:
		void LogFinisher::operator=(LogMessage& other)
		{
			other.Finish();
		}
	};

#define LOG(LEVEL)  GSE::LogFinisher()= GSE::LogMessage(LEVEL, __FILE__, __LINE__)
}